//#include<iostream>
#include"hope.h"
//global varible
#define LOG_ON false



extern "C"{
extern int InVal[];
extern FAULTPTR headfault;
extern int randomlimit;
extern void do_main(int argc,const char **argv);
 

vector<vector<int>> ots;//original test set
vector<vector<tuple<int,int>>> fts;//fliped test set.
uint16_t pattern_pos;
bool is_flip;
uint32_t flip_point;
bool is_undected_mod;


//
unordered_map<uint32_t,uint32_t> fault_map;
vector<unordered_set<uint32_t>> odfl;
//
//---------------------------------------------------
//
bool gNEW_CODE;
vector<unordered_set<uint32_t>> ndfl;
vector<tuple<int,int>> nflip; //flip bit bye step[pattern,pos]
int nstep;
int nx;

FAULTPTR ahash_gate(uint32_t value);
//put the gate into a integer
uint32_t hash_gate(FAULTPTR g)
{

	uint32_t value=g->gate->index;
	value|=(g->line+1)<<24;
	value|=g->type<<30;
	//auto f=ahash_gate(value);
	return value;
}
//It is oposit with the function hash_gate
extern GATEPTR *net;
FAULTPTR ahash_gate(uint32_t value)
{
	FAULTPTR g=new FAULTTYPE;
	g->gate=net[value&0xffffff];
	g->line=static_cast<int32_t>((value>>24)&0x3f)-1;
	g->type=value>>30;
	g->next=NULL;
	g->event=NULL;
	return g;
}

void init_ots(const string &filename)
{	
	ots.clear();
	ifstream ots_in(filename);
	if(!ots_in)
		ERR_MSG(filename+":cannot open");
	
	string line;
	vector<int> pattern;
	while(ots_in>>line)
	{
		int i=0;
		while(line.at(i)!=':')
			i++;
		i++;
		pattern.clear();
		for( ;i<line.size();i++)
			pattern.push_back(line.at(i)-'0');
		ots.push_back(pattern);
		
	}
}

void init_fts(const string &filename)
{	
	fts.clear();
	ifstream fts_in(filename);
	if(!fts_in)
		ERR_MSG(filename+":cannot open");
	
	string line;
	while(fts_in>>line)
	{
		vector<tuple<int,int>> position;
		for(int i=0;i<line.size();i++)
			if(line.at(i)=='1')
				position.push_back(make_tuple(i,0));
		fts.push_back(position);
	}
	
}	
//get_random_pattern
void get_pattern()
{
	if(is_flip)
	{
		flip_point++;
	  int flip_pos=get<0>(fts.at(pattern_pos).at(flip_point));
	  int &element=ots.at(pattern_pos).at(flip_pos);
	  element^=1;
	  //
	  vector<int> &pattern=ots.at(pattern_pos);
	  for(int i=0;i<pattern.size();i++)
	  {
	  		InVal[i]=pattern.at(i);
	  	}
	  	element^=1;
	  
	 }
	 else if(gNEW_CODE)
	 {
	 	
	 	vector<int> &pattern=ots.at(get<0>(nflip[nx]));
	 	for(int i=0;i<pattern.size();i++)
	 		InVal[i]=pattern.at(i);
		InVal[get<1>(nflip[nx])]^=1;
		nx++;
	 }
	 else
	 {	
	 	pattern_pos++;
	 	vector<int> &pattern=ots.at(pattern_pos);
	 	for(int i=0;i<pattern.size();i++)
	 		InVal[i]=pattern.at(i);
	 	//
	 	
	 }
}
//print  detected fault
//need init head
void push_detected_fault(FAULTPTR f)
{
	uint32_t value=hash_gate(f);
	if(is_flip)
		get<1>(fts.at(pattern_pos).at(flip_point))--;
	else if(gNEW_CODE){
		ndfl.at(nx-1).insert(value);	
	}
	else{
		odfl.at(pattern_pos).insert(value);
		auto p=fault_map.find(value);
		if(p==fault_map.end())
		{
			fault_map[value]=1;
		}
		else
			p->second++;
		}
}

void push_undetected_fault(FAULTPTR f)
{
}

//read fault
void get_fault_list()
{////
	//free headfault
	while(!headfault)
	{
		FAULTPTR faultptr=headfault->next;
		delete headfault;
		headfault=faultptr;
	}
	headfault=new FAULTTYPE;
	headfault->next=NULL;
	//cout<<"pattern_pos:"<<pattern_pos<<endl;
	if(is_undected_mod){
	for(auto &e:fault_map)
	{
		auto g=ahash_gate(get<0>(e));
		g->next=headfault->next;
		headfault->next=g;
	}
	}else{
		
	auto &fl=odfl.at(pattern_pos);
	for(auto &e:fl)
	{
		auto g=ahash_gate(e);
		//cout<<g->gate->symbol->symbol<<',';
		g->next=headfault->next;
		headfault->next=g;
	}
	}//else !undetected_fault
}
}//exetrn "C"

bool get_every_pattern_detected_fault(const string &filename,bool NEW_CODE)
{
cout<<__FUNCTION__<<endl;
gNEW_CODE=NEW_CODE;
nflip.clear();
if(NEW_CODE){
	for(int i=0;i<fts.size();++i)
		if(nstep<fts[i].size())
		{
			nflip.push_back(make_tuple(i,get<0>(fts[i][nstep])));
		}
	cout<<"nflip:"<<nflip.size()<<endl;
	if(nflip.empty())
		return false;
	ndfl.clear();
	ndfl.resize(nflip.size());
	nx=0;
	randomlimit=nflip.size();
	const char *argv[4]={"nul","-D","-N"};
	argv[3]=filename.c_str();
	int argc=4;
	do_main(argc,argv);
//	for(int i=0;i<ndfl.size();++i)
//	cout<<get<0>(nflip[i])<<':'<<ndfl[i].size()<<' ';
//	cout<<endl;
	return true;
}
	pattern_pos=-1;
	is_flip=false;
	flip_point=-1;
	randomlimit=ots.size();
	fault_map.clear();
	odfl.clear();
	odfl.resize(ots.size());
	const char *argv[4]={"nul","-D","-N"};
	argv[3]=filename.c_str();
	int argc=4;
	do_main(argc,argv);
	for(int i=0;i<fts.size();++i)
	{
		for(auto &x:fts.at(i))
			get<1>(x)=odfl[i].size();
	}
	cout<<"fault number:\t"<<fault_map.size()<<endl;
	return true;
}

void get_flip_pattern_detected_fault(const string &filename)
{	
cout<<__FUNCTION__<<'\n';
	for(int i=0;i<ots.size();i++){
	pattern_pos=i;
	is_flip=true;
	flip_point=-1;
	randomlimit=fts.at(i).size();
	const char *argv[6]={"nul","-D","-N","-f","fn"};
	argv[5]=filename.c_str();
	int argc=6;
	do_main(argc,argv);
	}

}

void get_undetected_fault(const string &filename)
{
}
